Slidevでスライド作ったら使い回しやすかった
Slidev とは?
Slidev を使えば、Markdownでスライドを作成できます。
Vueでコンポーネントを作ってスライドに表示させたり、
Windi CSSでclass属性にスタイルを記述できます。
良かった点
Vueは2年ぶりぐらい、初Windi CSSの筆者でも使えました。
良かった点を先にまとめておきます。
- Markdownで書ける
- 使い慣れたテキストエディタで編集できる
- GitHubで管理できる
- レイアウト・コンポーネントにより使い回しがしやすい
- サイズやレイアウトがテキストとして可視化される
インストール
Installation | Slidevに従い、インストールします。
npm init slidev@latest
以下のコマンドでブラウザが開き、スライドが表示されます。
npm run dev
ディレクトリ構成
公式ドキュメントを参考に作成したディレクトリ構成が以下です。
./ |-- .gitignore |-- .npmrc |-- README.md |-- components | `-- MyKbd.vue |-- global-bottom.vue |-- layouts | |-- cover.vue | |-- end.vue | |-- intro.vue | `-- two-col-with-gif.vue |-- netlify.toml |-- package-lock.json |-- package.json |-- public | |-- hoge.png | |-- foo.png | `-- ... |-- setup | `-- windicss.ts |-- slides-export | |-- 01.png | |-- 02.png | `-- ... |-- slides-export.pdf |-- slides.md `-- vercel.json
以下、手を加えたファイルや自動では作成されないものについて説明します。
slides.md, slides-export.pdf, slides-export/
slides.md にスライドの内容を書きます。
npx slidev export
を実行することで、slides-export.pdfが生成されます。
package.jsonに同様のコマンドが記述されているため、npm run export
でもPDF出力が可能です。
初回はnpm i -D playwright-chromium
でインストールが必要です。
npx slidev export --format png
を実行すると slides-exportディレクトリが作成され、PNG画像として出力できます。
ファイル名は 01.png, 02.png のように連番です。
npx slidev export --help
でより詳しくオプションを見ることができます。
.gitignore
作成された.gitignoreで指定されていない以下の2つを書き加えました。
- 出力したPDFファイル
slides-export.pdf
- PNG画像の入ったディレクトリ
slides-export
components/MyKbd.vue
自分で作成したコンポーネントファイルです。
global-bottom.vue
すべてのスライドの下側に表示する内容を書いたファイルです。
layouts/
スライドのレイアウトを定義したvueファイルを入れるディレクトリです。
public/
画像を入れるディレクトリです。
setup/windicss.ts
Windi CSSの設定をするためのファイルです。
設定とスライド例
スライド記述の基本構成
slides.mdにスライドを記述します。
スライド(ページ)を増やすには、スライド間に---
の行を加えます。
各スライドに設定(レイアウトの変更など)をする場合は、---
の代わりにFront Matter(---
で挟んでyamlを書く形式)を使います。
すべてのスライドに共通する設定(テーマやフォントなど)は、最初のスライドのFront Matterにまとめて書きます。
以下、スライド記述ファイルの例を簡単に示します。
--- theme: seriph layout: hoge --- # タイトル ## サブタイトルや発表者名 最初のスライドのレイアウトをhogeに指定した。 --- layout: center --- # 2番目のスライドの見出し 2番目のスライドの本文。レイアウトをcenterに指定した。 --- 3番目のスライドの本文。設定なしであるため、スライド区切りは`---`のみ。 --- 4番目のスライドの本文。 ...
Prettier を使うと ページ区切りのためのFront Matterが勝手に変換されてしまうため、適宜無効にしましょう。
すべてのスライドに共通する設定
今回はテーマをseriph
、フォントにヒラギノ丸ゴ ProN W4
を指定しました。
--- theme: seriph fonts: sans: "HiraMaruProN-W4" --- ここから1枚めのスライドの本文。
フォントを変更した場合は、もう一度npm run dev
を実行する必要があります。
フォントの指定にはPostScript名を書くようです。
以下はMacのFont Book.appのフォント情報の表示例です。
フォントの指定は package.json
で行う方法もあります。
参考:
最初のスライド
実装を見ると、
1枚目のスライドでレイアウトを指定しない場合はデフォルトのレイアウトではなくcover
になるようです。
レイアウトcover
では
h1
やp
タグについて設定されています。
以下、スライド例です。
--- theme: seriph fonts: sans: "HiraMaruProN-W4" --- # この世、 # ショートカットキー # 多すぎ ## えーたん
1枚目のスライドであるため、全体設定のtheme
やfonts
のFront Matterを含みます。
上記ではタイトルを改行して表現するため#
を3つ使いましたが、br
タグでも可能です。
別のレイアウトを試す
今度は中央に配置するためのレイアウトcenter
を使う例です。
--- layout: center --- # 一日どれくらい スクロール していますか?
画像を表示する
ローカルの画像はpublic
ディレクトリに入れ、/hoge.png
のように指定します。
--- layout: center --- ![mouse](/computer_mouse_top.png)
画像サイズを指定する場合はimg
タグを使い、class属性にWindi CSSでサイズを書きます。
Windi CSSでは、高さはh-xx
のように指定します。
詳しくは Sizing | Windi CSS をご覧ください。
今回はh-80
を指定しました。
--- layout: center --- <img class="h-80" src="/trackpad.jpg">
w-50
のように 高さではなく幅を使うこともできます。
GUIのスライド作成ツールでは、画像ファイルをD&Dしたりメニューをポチポチする必要があります。
Slidevでは、スニペットを使ったりコピー&ペーストして数文字編集するだけで画像を追加できます。
逆に、GUIのスライド作成ツールでは 図形や吹き出しの追加が数クリックで簡単に行えますが、
Slidevはそれらも画像として用意したりコードとして書く必要があります。
線と矢印についてはSlidevのPresenter Modeで追加できます(後述)。
参考:
flex で並べ、フォントサイズも変える。
要素の横並びはflex
やgrid
を使い、フォントサイズはtext-hoge
のように指定します。
詳しくは Flexbox | Windi CSS 、 Typography | Windi CSS をご覧ください。
--- layout: center --- # この世、ショートカットキー多すぎ <div class="text-2xl"> 全部は覚えられない、、、 </div> <div class="flex"> <img class="h-72" src="/pien.png"> <img class="h-72" src="/many-shortcut-key.png"> </div>
文字の背景色を変える
文字の背景色を変えるには、div
タグで囲み
Windi CSS の Background Colorで指定します。
今回は黄色にするためbg-yellow-300
を指定しました。
--- layout: center --- <div class="text-7xl flex items-center space-x-5"> <div class="bg-yellow-300 text-center leading-32 h-32 w-24">j</div> <div class="bg-yellow-300 text-center leading-32 h-32 w-24">k</div> <p>をセットで覚える</p> </div>
コンポーネントとレイアウトを使ってみる
VueのコンポーネントとSlidevのレイアウトを自分で作ってみます。
まず、完成したスライドが以下です。
このスライドに登場する主な要素は5つです。
- 見出し
- Markdownの
#
(h1
タグに相当)で書く - スライドの一番上の「Google Calendar」
- Markdownの
- 「黄色の背景に文字」+「文字」の組み合わせが左右に並んだもの
- スライドの「j:次の日」「k:前の日」
- ショートカットキーの動作を示すためのGIF
- GIFの右にある説明
- 任意の要素を入れられるようにします
- スライドの「d:[日]ビュー」の部分で、これも「黄色の背景に文字」+「文字」の組み合わせです
- 「黄色の背景に文字」+「文字」の組み合わせの背景が緑になったもの
- スライド右下の「?:ショートカットのヘルプ」
コンポーネント
まずは、スライドの2,4,5に共通する「黄色の背景に文字」+「文字」をコンポーネント化します。
コンポーネントはcomponents
ディレクトリに配置します。
今回はファイル名をMyKbd.vue
としました。
なお、最初から使えるコンポーネントの説明は Components | Slidev に、 実装は GitHub slidevjs/slidev にあります。
<script setup lang="ts"> import { computed } from "@vue/reactivity"; const props = defineProps<{ height: number; width?: number; keybind: string; textSize: string; }>(); const keyClass = computed(() => { let width = props.width; if (!width) { width = props.height; } return `bg-yellow-300 text-center leading-${props.height} h-${props.height} w-${width}`; }); const textClass = computed(() => { return `flex items-center ${props.textSize}`; }); </script> <template> <div v-bind:class="textClass"> <div v-bind:class="keyClass"> {{ props.keybind }} </div> <slot /> </div> </template>
簡単なコード説明
{{ props.keybind }}
では、受け取ったプロパティをそのままテキスト展開しています。
script
タグの中でクラス名を返す変数書くことで、template
タグの中のv-bind:class=hoge
の部分でクラスを動的に指定できます。
slot
タグを入れることで、MyKbd
開始タグと終了タグの間に書いた要素をslot
タグと置き換えができます。
クラスを動的に指定するため、Windi CSSのsafelist
を使いました。
SlidevのWindi CSSの設定はsetup/windicss.ts
にdefineWindiSetUp
を使って書きます。
import { defineWindiSetup } from '@slidev/types' export default defineWindiSetup( ()=> ({ safelist: "h-20 w-20 w-30 leading-20" }))
参考:
ここで、コンポーネントを使わずに書いた例、使って書いた例を出します。
コンポーネントを使わずに書く例:
<div class="flex items-center text-3xl"> <div class="bg-yellow-300 text-center leading-12 h-12 w-12"> d </div> ショートカットキーの説明文 </div>
コンポーネントを使って書く例:
<MyKbd keybind="d" height=12 textSize="text-3xl"> ショートカットキーの説明文 </MyKbd>
コンポーネントを使うことで、(適切な名前をつけていれば)何を表す部分か分かりやすくなります。
また、一ヵ所修正するだけで複数ページの要素をまとめて更新できるため、使い回しやすいです。
さらに、別の発表のスライドで使い回す時にも便利です。
コンポーネントなしで使い回す場合は、slides.mdから該当部分を探しテキストを範囲選択してからコピー&ペーストする必要があります。
コンポーネントありの場合は、コンポーネントファイルをコピー&ペーストするだけです。
レイアウトを作る
続いて、レイアウトを作成します。
レイアウトはlayouts
ディレクトリに配置します。
なお、最初から使えるレイアウトの説明は公式ドキュメント Layouts ・ Directory Structure に、
実装は GitHub slidevjs/slidev にあります。
今回はファイル名をtwo-col-with-gif.vue
にしました。
レイアウトの実装例
<script setup lang="ts"> interface Props { help_key?: string; } const props = withDefaults(defineProps<Props>(), { help_key: "?", }); </script> <template> <div class="slidev-layout"> <!-- 縦に要素を並べる --> <div class="h-full flex flex-col"> <!-- 1. 見出し --> <slot name="title" /> <!-- 2. 「黄色の背景に文字」+「文字」の組み合わせが左右に並んだもの --> <div class="grid grid-cols-2"> <!-- ショートカットキー 1 --> <MyKbd keybind="j" height="12" textSize="text-3xl"> : <slot name="j_feature" /> </MyKbd> <!-- ショートカットキー 2 --> <MyKbd keybind="k" height="12" textSize="text-3xl"> : <slot name="k_feature" /> </MyKbd> </div> <!-- 下寄せ かつ 左右の端に要素を並べる --> <div class="mt-auto flex justify-between"> <!-- 3. GIF --> <slot /> <!-- 縦に要素を並べる --> <div class="flex flex-col"> <!-- 上下中央 --> <div class="my-auto"> <!-- 4. 説明欄 --> <!-- ショートカットキー 3 --> <slot name="description" /> </div> <!-- 5. ショートカットキーのヘルプ --> <!-- 背景緑で中央に配置 --> <div class="flex items-center bg-lime-300 h-12 p-4"> <!-- ショートカットキー 4 --> <MyKbd v-bind:keybind="props.help_key" height="8" textSize="text-xl" > : <slot name="help_description"> ショートカットのヘルプ </slot> </MyKbd> </div> </div> </div> </div> </div> </template>
コンポーネントと違い、レイアウトの引数は各スライドのFront Matterの中で渡します。
以下の例では、レイアウトtwo-col-with-gif
へ 引数help_key
として文字列:h
を渡しています。
--- layout: two-col-with-gif help_key: ":h" ---
slidev-layout
クラスは 最初から使えるレイアウトの半分以上に使われており、
h1
やli
、table
などの基本的なタグにスタイルを当てています。
GitHub slidevjs/slidev で実装を見ることができます。
slotの中身をslides.mdで書く場合は、template
タグで囲むか、::hoge::
の下に書きます。
たとえば、レイアウトの中に書いたname="j_feature"
スロットの内容は、slides.mdでは::j_feature::
の下に書きます(例は後述)。
::hoge::
記法のパースの実装 を見ると、
スロットのnameは「アルファベット、数字、アンダースコア」のいずれかの文字しか使えないようです。
x: <slot name="j-feature"></slot> o: <slot name="j_feature"></slot>
新しいレイアウトファイルを追加したらrestartで反映しましょう。
自作のコンポーネントとレイアウトを使った例
自作のコンポーネントMyKbd
とレイアウトtwo-col-with-gif
を使って書いた例です。
--- layout: two-col-with-gif --- ::title:: # Google Calendar ::j_feature:: 次の日 ::k_feature:: 前の日 ::default:: <img class="h-88" src="/google-calendar.gif"> ::description:: <MyKbd keybind="d" height=12 textSize="text-3xl"> :[日]ビュー </MyKbd>
長くなるため、自作のコンポーネントとレイアウトを使わずに書いた例は折りたたみで表示します。
自作のコンポーネントとレイアウトを使わずに書いた例
--- layout: default --- <!-- 縦に要素を並べる --> <div class="h-full flex flex-col"> <!-- 1. 見出し --> <h1>Google Calendar</h1> <!-- 2. 「黄色の背景に文字」+「文字」の組み合わせが左右に並んだもの --> <div class="grid grid-cols-2"> <!-- ショートカットキー 1 --> <div class="flex items-center text-3xl"> <div class="bg-yellow-300 text-center leading-12 h-12 w-12">j</div> : <p>次の日</p> </div> <!-- ショートカットキー 2 --> <div class="flex items-center text-3xl"> <div class="bg-yellow-300 text-center leading-12 h-12 w-12">k</div> : <p>前の日</p> </div> </div> <!-- 下寄せ かつ 左右の端に要素を並べる --> <div class="mt-auto flex justify-between"> <!-- 3. GIF --> <img class="h-88" src="/google-calendar.gif"> <!-- 縦に要素を並べる --> <div class="flex flex-col"> <!-- 上下中央 --> <div class="my-auto"> <!-- 4. 説明欄 --> <!-- ショートカットキー 3 --> <div class="flex items-center text-3xl"> <div class="bg-yellow-300 text-center leading-12 h-12 w-12">d</div> :[日]ビュー </div> </div> <!-- 5. ショートカットキーのヘルプ --> <!-- 背景緑で中央に配置 --> <div class="flex items-center bg-lime-300 h-12 p-4"> <!-- ショートカットキー 4 --> <div class="flex items-center text-xl"> <div class="bg-yellow-300 text-center leading-8 h-8 w-8">?</div> : ショートカットのヘルプ </div> </div> </div> </div> </div>
レイアウトもコンポーネント同様、 何を表すのかはっきりしたり、複数ページの要素をまとめて更新できたり、使い回しやすくなります。
複雑なレイアウトやページによってレイアウトの違うスライドはslides.mdに書く量が増えるため注意です。
最後のスライド
Slidevではslides.mdで書いたスライドのほか、レイアウトend
のスライドが最後に自動で追加されます。
slides.mdで書いたスライドが12
ページ分であれば、レイアウトend
のスライドのページ番号は13
になります。
発表時のツールバーには 1 / 12
→ 2 / 12
→ ...→ 12 / 12
→ 13 / 12
とページ番号が表示されます。
いきなり本番で使うと混乱するので注意しましょう。
同名のレイアウトを実装した場合はローカルが優先となるため、layouts/end.vue
を配置すれば書き換えることができます。
ページ番号を入れる
ページ番号を入れるには、全スライド(ページ)に表示させる要素を書くglobal-top.vue
かglobal-bottom.vue
を使います。
前者はの上、後者は下に表示されます。
以下のコードは Global Layers | Slidev より引用です。
ページの左下に現在のページ数 / 全ページ数
を表示します。
<template> <footer v-if="$slidev.nav.currentLayout !== 'cover'" class="absolute bottom-0 left-0 right-0 p-2" > {{ $slidev.nav.currentPage }} / {{ $slidev.nav.total }} </footer> </template>
$slidev
が Sidev のページや設定を保持している変数です。
Vue Global Context | Slidev で詳しく見ることができます。
npm run dev
(=slidev --open
) を実行中に./global-bottom.vue
を作成した場合、再実行する必要があります。
GUIのスライド作成ツールでは 編集しているスライドが何ページ目かをすぐに把握できますが、
Slidevでは 編集しているslides.mdとブラウザでのプレビューを照らし合わせて確認します。
発表ツール
スライド下のツールバー
もしくはnpm run dev
実行時に表示されるURL(例:`http://localhost:3030/presenter`)で Presenter Mode を開けます。
Presenter Modeを開くと以下の5つが表示されます。
- 現在表示しているスライド
- 現在表示しているスライドのノート
- 次のスライド
- 経過時間
- ツールバー
経過時間は右上に表示され、タブが開かれた瞬間からスタートです。 リセットするには時間の左にあるリセットボタンをクリックします。
発表者ノート
各スライド(ページ)の最後のコメントがノートとしてPresenter Modeで表示されます。
--- # h1タグ。Windi CSS では text-4xl です <!-- これはただのコメントで、ノートにはならない --> 本文はpタグになります。 <!-- 各スライドの最後のコメントのみノートになる asdfdkfjdls<br> sdjflsdjfs -->
ノートでの改行もMarkdownのようです。
行末半角スペース2つか、br
タグです。
線や矢印をペイントできます。
マウスカーソルの巨大化もできますが、Google Slidesのレーザーポインタのような機能はありませんでした。
その他
リンク集
よく開いた公式ドキュメントのページのリンクをまとめておきます。
- Markdown Syntax | Slidev
- Typography | Windi CSS
- Slots | Vue.js
- 最初から入っているコンポーネントの実装
- 最初から入っているレイアウトの実装
日本語のSlidev公式ドキュメント もあります。
情報を探す時
Slidevについての情報を探すとき、ググるとGoogle Slidesやパワポの情報も出てくることがあります。
筆者は以下のようにして情報を探しました。
- 公式ドキュメント 内の検索機能を活用
- Google検索でサイト指定
site:sli.dev hoge
slidev hoge
ではなくsli.dev hoge
のようにURLに合わせてピリオドを入れて検索- GitHub リポジトリ の実装を見る
スライドの内容
スライドの内容は、社内のLTで発表したものを抜粋して作成しました。
気になった方は以下のリンクの記事版をどうぞ。
書いたコードのGitHubのリンクは以下です。